/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../xos/head.h"
#include "dynamic_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    ////////////////////////////////////////////////////////////////////////////////////
    // 

    static dynamic_impl::ITEM_DATA xos_item_data;

    ////////////////////////////////////////////////////////////////////////////////////
    //

    dynamic_impl::dynamic_impl()
    {
        m_szFullPath[0] = 0;
        m_szFileName[0] = 0;
        m_hModule = 0;
    }

    dynamic_impl::~dynamic_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int dynamic_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    int dynamic_impl::init()
    {
        int nRet = 0;
        return nRet;
    }

    int dynamic_impl::term()
    {
        int nRet = 0;

        m_szFullPath[0] = 0;
        m_szFileName[0] = 0;
        free();

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    // 
    // combine load and get_proc_by_name.
    // 
    // 1.try to load : lpszPath/lpszFileName.ext
    // 
    int dynamic_impl::load_and_get( void ** ppv, const char * lpszPath, const char * lpszFileName, const char * lpszProcName, const char * lpszExt )
    {
        void * pRet = 0;
        int ret = 0;

        xos::i_misc * pMisc = mgr::get()->misc();
        xos::i_crt * pCrt = mgr::get()->crt();
        char szPath[10240] = { 0 };

        if( 0 == ret )
        {
            if( !lpszPath )
            {
                pMisc->get_process_path( szPath, sizeof( szPath ) / sizeof( szPath ), 0 );
            }
            else
            {
                pCrt->strcpy( szPath, sizeof( szPath ), lpszPath );
            }
        }

        if( 0 == ret )
        {
            ret = load( szPath, lpszFileName, lpszExt );
        }

        if( 0 == ret )
        {
            ret = get_proc_by_name( &pRet, lpszProcName );
        }

        if( 0 == ret )
        {
            *ppv = pRet;
        }

        return ret;
    }

    int dynamic_impl::load( const char * lpszFullPath, const char * lpszFile, const char * lpszExt )
    {
        using namespace std;
        int ret = 0;

        xos::i_misc* pMisc = mgr::get()->misc();
        char szFile[10240] = { 0 };

        ////////////////////////////////////////////////////////////
        // 载入DLL

        if( 0 == ret )
        {
            strcpy( szFile, lpszFullPath );
            strcpy( m_szFileName, lpszFile );
            strcat( m_szFileName, "." );
#if defined(XOS_MAC) || defined(XOS_IOS_STATIC) || defined(XOS_IOS_SIMULATOR)
            strcat( m_szFileName, lpszExt ? lpszExt : "dylib" );
#else
            strcat( m_szFileName, lpszExt ? lpszExt : "so" );
#endif
            pMisc->path_append( szFile, sizeof( szFile ), m_szFileName );
            ret = load( szFile );
        }

        if( 0 == ret )
        {
            strcpy( m_szFullPath, lpszFullPath );
        }

        return ret;
    }

    //
    // 方便函数，感觉之前的实现有毛病，太复杂了
    // 
    int dynamic_impl::load_and_get( void ** ppv, const char * lpszFullFile, const char * lpszProcName )
    {
        int ret = 0;

        void * pRet = 0;

        if( 0 == ret )
        {
            ret = load( lpszFullFile );
        }

        if( 0 == ret )
        {
            ret = get_proc_by_name( &pRet, lpszProcName );
        }

        if( 0 == ret )
        {
            *ppv = pRet;
        }

        return ret;
    }

    int dynamic_impl::load( const char * lpszFullFile )
    {
        using namespace std;
        int ret = 0;
        m_hModule = dlopen( lpszFullFile, RTLD_LAZY );
        if( !m_hModule )
        {
            cout << "module is null" << endl;
            cout << "error = " << dlerror() << endl;
            ret = 1;
        }
        return ret;
    }

    int dynamic_impl::get_proc_by_name( void ** ppv, const char * lpszProcName )
    {
        void * pRet = 0;
        int nRet = 0;

        if( 0 == nRet )
        {
            if( !lpszProcName || ( 0 == strlen( lpszProcName ) ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            pRet = dlsym( m_hModule, lpszProcName );
            if( !pRet )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            *ppv = pRet;
        }

        return nRet;
    }

    // 
    // get full path and file name
    // 
    const char * dynamic_impl::get_full_path( char * lpszFullPath, int nBufSize )
    {
        int ret = 0;

        xos::i_crt* pCrt = mgr::get()->crt();

        if( ( 0 == ret ) && lpszFullPath )
        {
            pCrt->strcpy( lpszFullPath, nBufSize, m_szFullPath );
        }

        return m_szFullPath;
    }

    const char * dynamic_impl::get_file_name( char * lpszFileName, int nBufSize )
    {
        int ret = 0;

        xos::i_crt* pCrt = mgr::get()->crt();

        if( ( 0 == ret ) && lpszFileName )
        {
            pCrt->strcpy( lpszFileName, nBufSize, m_szFileName );
        }

        return m_szFileName;
    }

    int dynamic_impl::free()
    {
        int nRet = 0;

        if( m_hModule )
        {
            dlclose( m_hModule );
            m_hModule = 0;
        }

        return nRet;
    }
} // xos
